/**
 * Logger is responsible for all printings in the firewall module.
 */
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/icmp.h>
#include <net/udp.h>
#include <net/tcp.h>
#include <net/route.h>

#include <linux/netfilter.h>

#include "log_trace.h"

int msg_mask[MSG_CTXT_NUM];

char *msg_ctxt_name[MSG_CTXT_NUM + 1] = 
{
    "GENERAL ", /* MSG_GENERAL */
    "ILLEGAL "  /* MSG_CTXT_NUM */
};

char *package_status_string[PACKAGE_STATUS_NUM + 1] = 
{
    "accepted", /* PACKAGE_ACCEPT */
    "denied", /* PACKAGE_DENY */
    "ILLEGAL "  /* PACKAGE_STATUS_NUM */
}; 

/********** MESSAGE FUNCTIONS ***********/

/**
 * log_session 
 * 
 * Parameters:  
 * ps - the package status (accepted/declined)
 * info - the package data
 *
 * Prints out received data
 */
void log_session(enum package_status ps, struct ipt_context_info *info,
                          const struct net_device *in,
                          const struct net_device *out,
                          const struct sk_buff *skb )
{	
	struct iphdr _iph, *ih;
	struct tcphdr _tcph, *th;
	int iphoff = 0 ;
	if (info == NULL)
	{
		OUT_ERROR("Not valid input data for logger.");
		return;
	}
	

	if (info->flags & IPCONTEXT_LOG)
	{
		msg_enable(MSG_GENERAL);
		



    	/* TODO: shell we use whole dump_packet function for displaying packet info? i don't want :)   Shulman. */ 
        ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
        if (ih == NULL) {
              /*  printk("TRUNCATED");*/
             return;
        }

        th = skb_header_pointer(skb, iphoff + ih->ihl * 4,
                                    sizeof(_tcph), &_tcph);
        if (th == NULL) { 
        /*
			printk("INCOMPLETE [%u bytes] ",
		            skb->len - iphoff - ih->ihl*4);     */ 
			return; 
        }
/* Max length: 10 "PROTO=TCP " */
/* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
/* Max length: 20 "SPT=65535 DPT=65535 " */
/* Max length: 25 "INCOMPLETE [65535 bytes] " */


		OUT_GEN(MSG_GENERAL,
			"IN=%s OUT=%s SRC=%u.%u.%u.%u DST=%u.%u.%u.%u PROTO=TCP SPT=%u DPT=%u RULE:PORT=%d PROTOCOL=%s ACTION:%s.",
			in  ? in->name : "",
            out ? out->name : "",
			NIPQUAD(ih->saddr), NIPQUAD(ih->daddr), 
			ntohs(th->source), ntohs(th->dest),
			info->port,
			info->protocol,
			package_status_string[ps]);
	}   
	else
	{   
		msg_disable(MSG_GENERAL);	
	}
		  
	return;
}
/* log_session */

/**
 * msg_enable
 * 
 * Parameters:  
 * ctxt - context number
 * 
 * Enables a msg context
 */
int msg_enable(enum msg_ctxt ctxt)
{
    if (ctxt >= MSG_CTXT_NUM || ctxt < 0) {
        OUT_ERROR("attempt to enable invalid msg context, ctxt=%d. max=%d\n",ctxt, MSG_CTXT_NUM);
        return -1;
    }
    msg_mask[ctxt] = 1;
    return 0;
}
/* msg_enable */

/**
 * msg_disable
 * 
 * Parameters:  
 * ctxt - context number
 * 
 * Disables a msg context
 */
int msg_disable (enum msg_ctxt ctxt)
{
    if (ctxt >= MSG_CTXT_NUM || ctxt < 0) {
	OUT_ERROR("attempt to disable invalid trace ctxt, ctxt=%d. max=%d\n", ctxt, MSG_CTXT_NUM);
        return -1;
    }

    msg_mask[ctxt] = 0;    
    return 0;
}
/* msg_disable */

/**
 * msg_change_all
 * 
 * Parameters:  
 * enable - option to apply
 * 
 * Disables/Enable all msg contexts
 */
int msg_change_all(int enable)
{
    int ctxt;

    for (ctxt = 0; ctxt < MSG_CTXT_NUM; ctxt++) 
    {
        if (enable) 
        {
            if (msg_enable(ctxt))
                return -1;
        } 
        else 
        {
            if (msg_disable(ctxt))
                return -1;
        }
    }
    
    return 0;
}
/* msg_change_all */
